package com.topnav.mc.admin.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.js.lib.cache.Cache;
import com.js.lib.result.Result;
import com.topnav.mc.admin.bean.cachebean.CacheDeviceFenceBean;
import com.topnav.mc.admin.bean.cachebean.CacheFencePolygonBean;
import com.topnav.mc.admin.bean.OrgFenceBean;
import com.topnav.mc.admin.dao.mapper.FenceMapper;
import com.topnav.mc.admin.entity.Fence;
import com.topnav.mc.admin.entity.FenceAlarm;
import com.topnav.mc.admin.entity.FencePolygon;
import com.topnav.mc.admin.entity.Organization;
import com.topnav.mc.admin.entity.bean.FenceBean;
import com.topnav.mc.admin.entity.bean.LogContentBean;
import com.topnav.mc.admin.entity.enums.EnumLogType;
import com.topnav.mc.admin.entity.enums.EnumOperateFunction;
import com.topnav.mc.admin.entity.param.FenceParam;
import com.topnav.mc.admin.security.PermissionGrade;
import com.topnav.mc.admin.service.*;
import com.topnav.mc.exception.ExceptionMsg;
import com.topnav.mc.uitls.ErrorResultUtil;
import com.topnav.mc.uitls.ExceptionUtil;
import com.topnav.mc.uitls.PermissionGradeUtil;
import com.topnav.mc.uitls.gps.Gps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.topnav.mc.base.mc.McServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: kenny
 * @Date: 2023/11/13 10:51
 */
@Service
public class FenceServiceImpl extends McServiceImpl<FenceMapper, Fence,FenceBean, FenceParam>
    implements IFenceService {
    @Resource
    private PermissionGradeUtil pmGradeUtil;
    @Resource
    private IOrganizationService organizationService;
    @Autowired
    private IFenceAlarmService fenceAlarmService;
    @Autowired
    private IFencePolygonService fencePolygonService;
    @Resource(name="sysCache")
    private Cache sysCache;
    @Autowired
    private IOperateLogService operateLogService;


    @Override
    public boolean beforeSave(Fence entity){
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());
        return true;
    }
    @Override
    protected void afterSave(Fence entity){
        QueryWrapper<FenceParam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("f.id",entity.getId());
        FenceBean fenceBean = this.getOneInfo(queryWrapper,false);
        this.saveToCache(fenceBean);
        operateLogService.saveLog(EnumLogType.ADD, EnumOperateFunction.FENCE,new LogContentBean().setName(entity.getFenceName()));
    };
    protected void afterUpdate(Fence entity){
        QueryWrapper<FenceParam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("f.id",entity.getId());
        FenceBean fenceBean = this.getOneInfo(queryWrapper,false);
        this.saveToCache(fenceBean);
        operateLogService.saveLog(EnumLogType.EDIT, EnumOperateFunction.FENCE,new LogContentBean().setName(entity.getFenceName()));
    };

    protected void afterDelete(Fence entity){
        this.removeFromCache(entity.getId());
        operateLogService.saveLog(EnumLogType.DELETE, EnumOperateFunction.FENCE,new LogContentBean().setName(entity.getFenceName()));
    };

    @Override
    public  boolean beforeUpdate(Fence entity){
        entity.setUpdateTime(new Date());
        return true;
    }
    @Override
    public  boolean beforeDelete(Fence entity){
/*        LambdaQueryWrapper<FenceAlarm> fenceAlarmWrapper = new LambdaQueryWrapper<>();
        fenceAlarmWrapper.eq(FenceAlarm::getFenceId,entity.getId());
        if (fenceAlarmService.getOne(fenceAlarmWrapper,false) != null){
            //此设备已有围栏报警数据, 不能删除
            throw ExceptionUtil.commonException(ExceptionMsg.ERROR_DELETE_FENCE_USED_BY_FENCEALARM);
        }

        LambdaQueryWrapper<FencePolygon> fencePolygonWrapper = new LambdaQueryWrapper<>();
        fencePolygonWrapper.eq(FencePolygon::getFenceId,entity.getId());
        if (fencePolygonService.getOne(fencePolygonWrapper,false) != null){
            //此围栏已有地图数据, 不能删除
            throw ExceptionUtil.commonException(ExceptionMsg.ERROR_DELETE_FENCE_USED_BY_PLOYGON);
        }*/
        return true;
    }

    /**
     * 根据部门ID查围栏树
     * @param pid
     * @return
     */
    @Override
    public  Result findFenceTree(String pid){
        List<OrgFenceBean> data = new ArrayList<>();
        //当前用户权限
        PermissionGrade permissionGrade = pmGradeUtil.getPmGrade();
        if (permissionGrade == null){
            return ErrorResultUtil.result(ExceptionMsg.ERROR_AUTHENTICATION_FAILE);
        }

/*        Organization organization = null;
        if (!StringUtils.isEmpty(pid)){
            String[] pids = pid.split("-");
            Long orgId = Long.valueOf(pids[1]);
            organization = organizationService.getById(orgId);
        }*/

        QueryWrapper<Organization> orgWrapper = new QueryWrapper<>();
        if (StringUtils.isEmpty(pid)){
            //第一级，非第一级
            if (permissionGrade.getPermissionLevel()==1 || permissionGrade.getPermissionLevel()==2){
                orgWrapper.eq("id",permissionGrade.getOrgId());
            }else if (permissionGrade.getPermissionLevel()==3 || permissionGrade.getPermissionLevel()==4){
                orgWrapper.eq("parent_id",permissionGrade.getOrgId())
                        .or()
                        .eq("id",permissionGrade.getOrgId());
            }else if (permissionGrade.getPermissionLevel()==9){
                //部门系统管理员
                orgWrapper.isNull("parent_id");
            }else if ("admin".equals(permissionGrade.getUserName().toLowerCase())){
                //部门系统管理员
                orgWrapper.isNull("parent_id");
            }
        }else{
            String[] pids = pid.split("-");
            orgWrapper.eq("parent_id",Long.valueOf(pids[1]));
        }
        orgWrapper.orderByAsc("path");

        //查询出单位列表
        List<Organization> orgList = organizationService.list(orgWrapper);
        for(Organization organization : orgList){
            OrgFenceBean orgFenceBean = new OrgFenceBean().setTitle(organization.getShortName())
                    .setId("O-"+organization.getId().toString())
                    .setType("org");
            orgFenceBean.getArrt().put("orgId",organization.getId());
            orgFenceBean.getArrt().put("orgCode",organization.getCode());
            orgFenceBean.getArrt().put("orgName",organization.getName());
            orgFenceBean.getArrt().put("shortName",organization.getShortName());
            orgFenceBean.getArrt().put("path",organization.getPath());
            if (permissionGrade.getPermissionLevel() >= 3){
                if (organization.getHasChild()){
                    orgFenceBean.setChildren(new ArrayList<OrgFenceBean>());
                }else{
                    QueryWrapper<Fence> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("org_id",organization.getId());
                    Fence fence = this.getOne(queryWrapper,false);
                    if (fence != null){
                        orgFenceBean.setChildren(new ArrayList<OrgFenceBean>());
                    }
                }
            }
            data.add(orgFenceBean);
        }

        //本部门下的围栏
        QueryWrapper<FenceParam> fenceWrapper = new QueryWrapper<>();
        if (StringUtils.isEmpty(pid)){
            if(permissionGrade.getPermissionLevel()==1) {
                fenceWrapper.eq("f.id",-1);
            }else if(permissionGrade.getPermissionLevel() >=2 && permissionGrade.getPermissionLevel() < 9){
                fenceWrapper.eq("f.org_id",permissionGrade.getOrgId());
            }else if(permissionGrade.getPermissionLevel()==9){
                fenceWrapper.isNull("f.org_id");
            }
        }else{
            String[] pids = pid.split("-");
            fenceWrapper.eq("f.org_id",Long.valueOf(pids[1]));
        }

        //当前目录下的设备
        List<FenceBean> fenceBeanList = this.listInfo(fenceWrapper);
        for(FenceBean fenceBean : fenceBeanList){
            OrgFenceBean orgFenceBean = new OrgFenceBean().setTitle(fenceBean.getFenceName())
                    .setId("F-"+fenceBean.getId().toString())
                    .setType("fence");
            orgFenceBean.getArrt().put("orgId",fenceBean.getOrgId());
            orgFenceBean.getArrt().put("orgCode",fenceBean.getOrgCode());
            orgFenceBean.getArrt().put("orgName",fenceBean.getOrgName());
            orgFenceBean.getArrt().put("shortName",fenceBean.getShortName());
            orgFenceBean.getArrt().put("path",fenceBean.getPath());
            orgFenceBean.getArrt().put("fenceId",fenceBean.getId());
            orgFenceBean.getArrt().put("fenceName",fenceBean.getFenceName());
            orgFenceBean.getArrt().put("fenceType",fenceBean.getFenceType());
            orgFenceBean.getArrt().put("fenceTypeDesc",fenceBean.getFenceTypeDesc());
            orgFenceBean.getArrt().put("coordinateSystem",fenceBean.getCoordinateSystem());
            orgFenceBean.getArrt().put("coordinate",fenceBean.getCoordinate());
            orgFenceBean.getArrt().put("note",fenceBean.getNote());
            //orgFenceBean.getArrt().put("fencePolygons",fenceBean.getFencePolygons());
            data.add(orgFenceBean);
        }
        return Result.ok(data);
    }

    /**
     * 按关键字查询围栏树
     * @param keyword
     * @return
     */
    @Override
    public Result searchBykeyword(String keyword){
        List<OrgFenceBean> data = new ArrayList<>();
        //当前用户权限
        PermissionGrade permissionGrade = pmGradeUtil.getPmGrade();
        if (permissionGrade == null){
            return ErrorResultUtil.result(ExceptionMsg.ERROR_AUTHENTICATION_FAILE);
        }
        //所有的部门
        List<Organization> allOrg = organizationService.list();
        Map<Long, Organization> orgsMap = allOrg.stream().collect(Collectors.toMap(Organization::getId, Function.identity(), (v1, v2)->v1));

        //查询单位
        List<Organization> organizations = this.getOrgByPerm(permissionGrade,keyword,null);
        //查询围栏
        List<FenceBean> fenceBeans = this.getFenceByPerm(permissionGrade,keyword,null);

        OrgFenceBean backBean = null;
        Map<String, OrgFenceBean> resultMap = new HashMap<>();
        for(Organization organization : organizations){
            backBean = null;
            String[] paths = organization.getPath().split("/");
            for(int i=paths.length-1;i>=0;i--){
                String id = "O-" + paths[i];
                OrgFenceBean bean = resultMap.get(id);
                if (bean == null){
                    bean = new OrgFenceBean();
                    resultMap.put(id,bean);
                }
                Organization org1 = orgsMap.get(Long.valueOf(paths[i]));
                bean.setTitle(org1.getShortName());
                bean.setType("org");
                bean.setId("O-"+paths[i]);
                bean.getArrt().put("orgCode",org1.getCode());
                bean.getArrt().put("orgName",org1.getName());
                bean.getArrt().put("shortName",org1.getShortName());
                bean.getArrt().put("path",org1.getPath());
                if (i==paths.length-1){
                    //最小的那一个
                    if (hasFenceInOrg(Long.valueOf(paths[i]))){
                        if (bean.getChildren() == null)
                            bean.setChildren(new ArrayList<>());
                    }
                }else{
                   if (backBean != null){
                       if (bean.getChildren() == null)
                           bean.setChildren(new ArrayList<>());
                       bean.getChildren().add(backBean);
                   }
                }
                backBean = bean;
                if (permissionGrade.getOrgId() != null && permissionGrade.getOrgId().equals(Long.valueOf(paths[i]))){
                    break;
                }
            }
        }


        return null;
    }

    final String fenceKey = "ORG_FENCE_KEY";
    @Override
    public void saveToCache(FenceBean fenceBean) {
        CacheFencePolygonBean bean = new CacheFencePolygonBean();
        bean.setId(fenceBean.getId());
        bean.setOrgId(fenceBean.getOrgId());
        bean.setPath(fenceBean.getPath());
        bean.setCoordinateSystem(fenceBean.getCoordinateSystem());
        bean.setCoordinates(this.tranBaseCordToGps(fenceBean.getCoordinate()));
        sysCache.hset(this.fenceKey,bean.getId().toString(),bean);
    }

    @Override
    public void saveAllToCache() {
        sysCache.del(this.fenceKey);
        List<FenceBean> beans = this.listInfo();
        for(FenceBean fenceBean :beans){
            this.saveToCache(fenceBean);
        }
    }
    @Override
    @Transactional
    public boolean removeById(Serializable id) {
        return super.removeById(id);
/*        Fence fence = this.getById(id);
        if (fence == null){return true;}
        if (!this.beforeDelete(fence)){return false;}
        this.removeRelate(fence);
        super.removeById(id);
        operateLogService.saveLog(EnumLogType.DELETE, EnumOperateFunction.FENCE,new LogContentBean().setName(fence.getFenceName()));
        return true;*/
    }
    @Override
    @Transactional
    public boolean remove(Wrapper<Fence> queryWarrper){
        return super.remove(queryWarrper);
/*        List<Fence> list = super.list(queryWarrper);
        for(Fence fence : list){
            this.removeRelate(fence);
            super.removeById(fence.getId());
            operateLogService.saveLog(EnumLogType.DELETE, EnumOperateFunction.FENCE,new LogContentBean().setName(fence.getFenceName()));

        }


      return true;*/
    }
    /**
     * 删除相关联数据
     * 围栏报警/围栏数据
     * @param fence
     */
    @Override
    public void removeRelate(Fence fence){
        //1、围栏报警
        LambdaQueryWrapper<FenceAlarm> alarmWrapper = new LambdaQueryWrapper<>();
        alarmWrapper.eq(FenceAlarm::getFenceId,fence.getId());
        fenceAlarmService.remove(alarmWrapper);
        //2.围栏数据
        LambdaQueryWrapper<FencePolygon> polygonWrapper = new LambdaQueryWrapper<>();
        polygonWrapper.eq(FencePolygon::getFenceId,fence.getId());
        fencePolygonService.remove(polygonWrapper);

    }

    @Override
    public void removeFromCache(Long id) {
        sysCache.hdel(this.fenceKey,id.toString());
    }

    @Override
    public CacheFencePolygonBean getFromCache(Long id){
        return (CacheFencePolygonBean)sysCache.hget(this.fenceKey,id.toString());
    }

    @Override
    public List<CacheFencePolygonBean> getAllFromCache() {
        Map<Object,Object> map = sysCache.hmget(this.fenceKey);
        List<CacheFencePolygonBean> result = new ArrayList<CacheFencePolygonBean>();
        if (map != null){
            for(Object obj : map.values()){
                result.add((CacheFencePolygonBean)obj);
            }
        }
        return result;
    }

    private boolean hasFenceInOrg(long orgId){
        QueryWrapper<Fence> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("org_id",orgId);
        return this.getOne(queryWrapper,false)==null?false:true;
    }




    /**
     * 由权限取得部门列表
     * @param permissionGrade
     * @param keyWord
     * @param pid
     * @return
     */
   private List<Organization> getOrgByPerm(PermissionGrade permissionGrade, String keyWord,String pid){
        QueryWrapper<Organization> orgWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(pid)){
            String[] pids = pid.split("-");
            orgWrapper.eq("parent_id",Long.valueOf(pids[1]));
        }else{
            if (!StringUtils.isEmpty(keyWord)){
                orgWrapper.like("name",keyWord);
            }
            //第一级，非第一级
            if (permissionGrade.getPermissionLevel()==1 || permissionGrade.getPermissionLevel()==2){
                orgWrapper.eq("id",permissionGrade.getOrgId());
            }else if (permissionGrade.getPermissionLevel()==3 || permissionGrade.getPermissionLevel()==4){
                orgWrapper.eq("parent_id",permissionGrade.getOrgId())
                        .or()
                        .eq("id",permissionGrade.getOrgId());
            }else if (permissionGrade.getPermissionLevel()==9){
                //部门系统管理员
                orgWrapper.isNull("parent_id");
            }else if ("admin".equals(permissionGrade.getUserName().toLowerCase())){
                //部门系统管理员
                orgWrapper.isNull("parent_id");
            }
        }
        orgWrapper.orderByAsc("path");

        //查询出单位列表
        return organizationService.list(orgWrapper);
    }

    /**
     * 查询围栏数据
     * @param permissionGrade
     * @param keyWord
     * @param pid
     * @return
     */
    private List<FenceBean> getFenceByPerm(PermissionGrade permissionGrade, String keyWord,String pid){
        //本部门下的围栏
        QueryWrapper<FenceParam> fenceWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(pid)) {
            String[] pids = pid.split("-");
            fenceWrapper.eq("org_id",Long.valueOf(pids[1]));
        }else{
            if (!StringUtils.isEmpty(keyWord)){
                fenceWrapper.like("name",keyWord);
            }
            if(permissionGrade.getPermissionLevel()==1) {
                fenceWrapper.eq("f.id",-1);
            }else if(permissionGrade.getPermissionLevel() >=2 && permissionGrade.getPermissionLevel() < 9){
                fenceWrapper.eq("f.org_id",permissionGrade.getOrgId());
            }else if(permissionGrade.getPermissionLevel()==9){
                fenceWrapper.isNull("f.org_id");
            }
        }
        return this.listInfo(fenceWrapper);
    }

    /**
     * Baes64转定位列表
     * @param base64Coordinate  [[[lng,lat],[lng,lat]]] 转码后
     * @return
     */
    private List<Gps> tranBaseCordToGps(String base64Coordinate){
        List<Gps> result = new ArrayList<>();
        BASE64Decoder decoder = new BASE64Decoder();
        try{
            byte[] decoderBytes = decoder.decodeBuffer(base64Coordinate);
            String s = new String(decoderBytes);
            if (!StringUtils.isEmpty(s)){
                //System.out.println(s.length());
                if (s.charAt(s.length()-1)!=']'){
                    s=s.substring(0,s.length()-1);
                }

                if (s.charAt(s.length()-1)!=']'){
                    s=s.substring(0,s.length()-1);
                }
                //System.out.println(s.length());
            }
            //System.out.println(s);
            JSONArray jsonArray = JSONArray.parseArray(s);
            //System.out.println(jsonArray.toString());
            //JSONArray
            for(int i=0;i<jsonArray.size();i++){
                JSONArray jsonArray1 =  (JSONArray)jsonArray.get(i);
                for(int j=0;j<jsonArray1.size();j++){
                    JSONArray jsonArray2 =  (JSONArray)jsonArray1.get(j);
                    //System.out.println(jsonArray2.toString());
                    Gps gps = new Gps();
                    gps.setLongitude(((BigDecimal) jsonArray2.get(0)).doubleValue());
                    gps.setLatitude(((BigDecimal)jsonArray2.get(1)).doubleValue());
                    result.add(gps);
                }
            }
            JSONObject jsonObject = JSONObject.parseObject(s);
            //System.out.println(jsonObject.toString());
        }catch (Exception e){
            System.out.println(e.toString());
        }
        return result;
    }

    private final String deviceFenceStatusKey = "DEVICE-FENCE-STATUS-KEY";
    /**
     * 保存设备围栏状态
     * @param bean
     */
    @Override
    public void setDeviceFenceStatusToCache(CacheDeviceFenceBean bean){
        sysCache.hset(this.deviceFenceStatusKey,bean.getDeviceId().toString() + "-" + bean.getFenceId(),bean,1*60*60L);
    }

    /**
     * 取得设备围栏状态
     * @param key // deviceId + "-" + fenceId
     */
    @Override
    public CacheDeviceFenceBean getDeviceFenceStatusFromCache(String key){
        return (CacheDeviceFenceBean)sysCache.hget(this.deviceFenceStatusKey,key);
    }

}
